package com.atguigu.mall.mallproduct.controller;

import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.UUID;

/**
 * @author fuc
 * @create 2020-11-20
 */
public class IndexController {

  @Autowired RedissonClient redisson;

  @Autowired StringRedisTemplate redisTemplate;

  /**
   * 保证一定能读到最新数据，修改期间，写锁是一个排它锁（互斥锁、独享锁）。读锁是一个共享锁 写锁没释放读就必须等待
   *
   * <p>读+读：相当于无锁，并发读，只会在redis中记录好，所有当前的读锁。他们都会同时加锁成功
   * 写+读：等待写锁释放
   * 写+写：阻塞方式
   * 读+写：有读锁。写也需要等待。
   * 只要有写的存在，都必须等待
   *
   */
  @GetMapping("/write")
  @ResponseBody
  public String writevalue() {
    RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
    String s = " ";
    RLock rLock = lock.writeLock();
    try {
      // 1.改数据加写锁，读数据加读锁
      rLock.lock();
      System.out.println("写锁加锁成功..." + Thread.currentThread().getId());
      s = UUID.randomUUID().toString();
      Thread.sleep(30000);
      redisTemplate.opsForValue().set("writeValue", s);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rLock.unlock();
      System.out.println("写锁释放..." + Thread.currentThread().getId());
    }
    return s;
  }

  @GetMapping("/read")
  @ResponseBody
  public String readvalue() {
    RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
    String s = " ";
    // 加读锁
    RLock rLock = lock.readLock();
    rLock.lock();
    System.out.println("读锁加锁成功..." + Thread.currentThread().getId());
    try {
      Thread.sleep(30000);
      s = redisTemplate.opsForValue().get("writeValue");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      rLock.unlock();
      System.out.println("读锁释放..." + Thread.currentThread().getId());
    }
    return s;
  }

  /** 车库停车， 3车位 信号量也可以用作分布式限流 */
  @GetMapping("/park")
  @ResponseBody
  public String park() throws InterruptedException {
    RSemaphore park = redisson.getSemaphore("park");
    // park.acquire(); // 获取一个信号，获取一个值，占一个车位
    boolean b = park.tryAcquire();
    if (b) {
      // 执行业务
    } else {
      return "error";
    }
    return "ok=>" + b;
  }

  @GetMapping("/go")
  @ResponseBody
  public String go() throws InterruptedException {
    RSemaphore park = redisson.getSemaphore(" park ");
    park.release(); // 释放一个车位
    return "ok";
  }

  /** 放假，锁门 1班没人了，2 5个班全部走完，我们可以锁大门 */
  @GetMapping("/lockDoor")
  @ResponseBody
  public String lockDoor() throws InterruptedException {
    RCountDownLatch door = redisson.getCountDownLatch("door");
    door.trySetCount(5);
    door.await(); // 等待闭锁都完成
    return "放假了...";
  }

  @GetMapping("/gogogo/{id}")
  public String gogogo(@PathVariable("id") Long id) {
    RCountDownLatch door = redisson.getCountDownLatch("door");
    door.countDown(); // 计数减一；
    return id + "班的人都走了...";
  }
}
